package com.huishu.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huishu.commons.config.cache.RedisUtil;
import com.huishu.commons.constant.RedisKeyPrefix;
import com.huishu.commons.exception.BaseException;
import com.huishu.commons.exception.NotFoundException;
import com.huishu.commons.pojo.Result;
import com.huishu.commons.pojo.dto.FindAvailableCouponDTO;
import com.huishu.commons.pojo.vo.CartItemGoodsVO;
import com.huishu.commons.pojo.vo.CouponVO;
import com.huishu.commons.pojo.vo.FullReductionVO;
import com.huishu.commons.utlis.BeanUtils;
import com.huishu.order.fegin.CouponFeignClient;
import com.huishu.order.fegin.GoodsFeignClient;
import com.huishu.order.mapper.CartItemMapper;
import com.huishu.order.pojo.dto.CartItemAddDTO;
import com.huishu.order.pojo.dto.NumberHandleDTO;
import com.huishu.order.pojo.dto.OrderSelectDTO;
import com.huishu.order.pojo.dto.UpdateSpecificationsDTO;
import com.huishu.order.pojo.model.CartItemDO;
import com.huishu.order.pojo.vo.CartItemListVO;
import com.huishu.order.pojo.vo.CartItemVO;
import com.huishu.order.service.ActivityDescriptionService;
import com.huishu.order.service.CartItemService;
import com.huishu.order.utils.AssistantContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author generator@ljj
 * @since 2023-04-10
 */
@Slf4j
@Service
public class CartItemServiceImpl extends ServiceImpl<CartItemMapper, CartItemDO> implements CartItemService {

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private Executor executor;

    @Autowired
    private GoodsFeignClient goodsFeignClient;

    @Autowired
    private CouponFeignClient couponFeignClient;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ActivityDescriptionService activityDescriptionService;

    @Override
    public Result add(CartItemAddDTO cartItemAddDTO) {
        // 样品只能购买一次
        Result result = goodsFeignClient.findGoodsById(cartItemAddDTO.getProductId());
        if (!result.getStatus()) {
            throw new BaseException("根据id查询商品失败!!");
        }
        Map<String, Object> entry = (Map<String, Object>) result.getEntry();
        Boolean isSample = MapUtils.getBoolean(entry, "isSample");
        if (isSample) {
            String hget = redisUtil.hget(RedisKeyPrefix.SAMPLE_LIMITATION + AssistantContext.getCurrentUid(), cartItemAddDTO.getProductId().toString());
            if (hget != null) {
                return Result.fail("当前商品每个ID限购1份");
            }
        }

        // 查询是否已经存在
        LambdaQueryWrapper<CartItemDO> queryWrapper = Wrappers.lambdaQuery(CartItemDO.class)
                .eq(CartItemDO::getUserId, AssistantContext.getCurrentUid())
                .eq(CartItemDO::getIsDelete, false)
                .eq(CartItemDO::getProductItemId, cartItemAddDTO.getProductItemId())
                .eq(CartItemDO::getProductId, cartItemAddDTO.getProductId());
        CartItemDO one = this.getOne(queryWrapper);
        // 样品只能购买一次
        if (one != null) {
            if (isSample) {
                return Result.fail("当前商品每个ID限购1份");
            }
            // 数量加1
            UpdateWrapper updateWrapper = new UpdateWrapper();
            updateWrapper.setSql("quantity = quantity+1");
            updateWrapper.eq("id", one.getId());
            boolean update = this.update(updateWrapper);
            return update ? Result.success(cartItemCount(AssistantContext.getCurrentUid())) : Result.fail("修改数量失败");
        }
        CartItemDO cartItemDO = BeanUtils.copyProperties(cartItemAddDTO, CartItemDO.class);
        cartItemDO.setUserId(AssistantContext.getCurrentUid());
        int insert = this.baseMapper.insert(cartItemDO);
        if (insert > 0) {
            redisUtil.incr(RedisKeyPrefix.CARTITEM_COUNT + AssistantContext.getCurrentUid(), 1);
            return Result.success(cartItemCount(AssistantContext.getCurrentUid()));
        }
        throw new BaseException("添加购物车插入数据失败");
    }

    /**
     * 购物车产品数量
     *
     * @return
     */
    @Override
    public Integer cartItemCount(Long userId) {
        LambdaQueryWrapper<CartItemDO> queryWrapper = Wrappers.lambdaQuery(CartItemDO.class)
                .eq(CartItemDO::getIsDelete, 0)
                .eq(CartItemDO::getUserId, userId);
        return this.baseMapper.selectCount(queryWrapper);
    }

    @Override
    public Result findCartItemList(Long userId) {
        BigDecimal totalPrice = new BigDecimal(0);
        BigDecimal totalReducePrice = new BigDecimal(0);
        String str = "再购买%s元，即可享%s";
        try {
            LambdaQueryWrapper<CartItemDO> queryWrapper = Wrappers.lambdaQuery(CartItemDO.class)
                    .eq(CartItemDO::getIsDelete, false)
                    .eq(CartItemDO::getUserId, userId);
            List<CartItemDO> cartItems = this.list(queryWrapper);
            if (CollectionUtils.isEmpty(cartItems)) {
                return Result.success();
            }
            List<Long> productItemIds = cartItems.stream().map(CartItemDO::getProductItemId).collect(Collectors.toList());

            // 查询是否有满增活动
            CompletableFuture<List<FullReductionVO>> future = CompletableFuture.supplyAsync(() -> {
                List<Long> collect = cartItems.stream().filter(CartItemDO::getIsSelect).map(CartItemDO::getProductId).collect(Collectors.toList());
                Result<List<FullReductionVO>> result = goodsFeignClient.find(collect);
                if (!result.getStatus()) {
                    throw new BaseException("查询满减活动数据异常");
                }
                return result.getEntry();
            }, executor);

            // 查询商品数据
            CompletableFuture<List<CartItemGoodsVO>> future1 = CompletableFuture.supplyAsync(() -> {
                Result<List<CartItemGoodsVO>> result = goodsFeignClient.findCartItemGoods(productItemIds);
                if (!result.getStatus()) {
                    throw new BaseException("查询商品数据异常");
                }
                return result.getEntry();
            }, executor);
            CompletableFuture<Void> allOf = CompletableFuture.allOf(future, future1);
            allOf.get();
            List<CartItemGoodsVO> cartItemGoods = future1.get();
            List<Long> productCategoryIds = cartItemGoods.stream().map(CartItemGoodsVO::getProductCategoryId).distinct().collect(Collectors.toList());
            // 查询当前购物车可用的优惠卷
            CompletableFuture<List<CouponVO>> future2 = CompletableFuture.supplyAsync(() -> {
                // List<Long> productIds = cartItemGoods.stream().map(CartItemGoodsVO::getProductId).distinct().collect(Collectors.toList());
                FindAvailableCouponDTO findAvailableCouponDTO = new FindAvailableCouponDTO();
                // findAvailableCouponDTO.setProductIds(productIds);
                findAvailableCouponDTO.setProductCategoryIds(productCategoryIds);
                Result<List<CouponVO>> result = couponFeignClient.findAvailableCoupon(findAvailableCouponDTO);
                if (!result.getStatus()) {
                    log.error("根据商品id查询优惠卷异常");
                    throw new NotFoundException("根据商品id查询优惠卷异常");
                }
                return result.getEntry();
            }, executor);

            // 查询我的优惠卷
            CompletableFuture<List<CouponVO>> future3 = CompletableFuture.supplyAsync(() -> {
                Result<List<CouponVO>> result = couponFeignClient.findCouponByUserId(userId, productCategoryIds);
                if (!result.getStatus()) {
                    log.error("查询我的优惠卷异常");
                    throw new NotFoundException("查询我的优惠卷异常");
                }
                return result.getEntry();
            }, executor);
            // 查询我的复购卷
            CompletableFuture<List<CouponVO>> future4 = CompletableFuture.supplyAsync(() -> {
                Result<List<CouponVO>> result = couponFeignClient.findRepurchaseByUserId(userId, productCategoryIds);
                if (!result.getStatus()) {
                    log.error("查询查询我的复购卷异常");
                    throw new NotFoundException("查询查询我的复购卷异常");
                }
                return result.getEntry();
            }, executor);
            CompletableFuture<Void> allOf1 = CompletableFuture.allOf(future2, future3, future4);
            allOf1.get();
            // 组合数据
            List<CartItemVO> cartItemsVOS = cartItems.stream().map(cartItemDO -> BeanUtils.copyProperties(cartItemDO, CartItemVO.class)).collect(Collectors.toList());
            Map<Long, CartItemGoodsVO> cartItemGoodsVOMap = cartItemGoods.parallelStream().collect(Collectors.toMap(CartItemGoodsVO::getId, cartItemGoodsVO -> cartItemGoodsVO));
            for (CartItemVO cartItemsVO : cartItemsVOS) {
                CartItemGoodsVO cartItemGoodsVO = cartItemGoodsVOMap.get(cartItemsVO.getProductItemId());
                if (cartItemsVO.getIsSelect()) {
                    totalPrice = totalPrice.add(cartItemGoodsVO.getPrice().multiply(new BigDecimal(cartItemsVO.getQuantity())));
                }
                maintenanceData(cartItemsVO, cartItemGoodsVO);
            }
            CartItemListVO cartItemListVO = new CartItemListVO();
            // 判断是否可以使用优惠卷
            setIsUseCoupon(cartItemsVOS, cartItemListVO);
            List<FullReductionVO> fullReductions = future.get();
            if (CollectionUtils.isNotEmpty(fullReductions)) {
                // 根据总金额获取满减活动
                fullReductions = fullReductions.stream().sorted(Comparator.comparing(FullReductionVO::getFullPrice).reversed())
                        .collect(Collectors.toList());
                cartItemListVO.setFullReductions(fullReductions);
                for (int i = 0; i < fullReductions.size(); i++) {
                    FullReductionVO fullReductionVO = fullReductions.get(i);
                    if (fullReductionVO.getFullPrice().compareTo(totalPrice) != 1) {
                        FullReductionVO fullReduction = fullReductions.get(i);
                        // 进行满减
                        totalPrice = totalPrice.subtract(fullReduction.getReducePrice());
                        totalReducePrice = fullReduction.getReducePrice();
                        cartItemListVO.setFullReductionGiveProducts(fullReduction.getGiveProducts());
                        if (i != 0) {
                            FullReductionVO fullReductionVO1 = fullReductions.get(i - 1);
                            BigDecimal subtract1 = fullReductionVO1.getFullPrice().subtract(totalPrice);
                            str = String.format(str, subtract1.toString(), fullReductionVO1.getName());
                            cartItemListVO.setFullReductionStr(str);
                        } else {
                            // 这里可以返回以满足多少多少
                            str = null;
                        }
                        break;
                    }
                }
                // 循环完成未获得满减信息 -- 总金额小于于所有满减金额
                if (str != null && str.contains("%s")) {
                    FullReductionVO fullReductionVO = fullReductions.get(fullReductions.size() - 1);
                    BigDecimal subtract = fullReductionVO.getFullPrice().subtract(totalPrice);
                    str = String.format(str, subtract.toString(), fullReductionVO.getName());
                    cartItemListVO.setFullReductionStr(str);
                }
            }
            List<CouponVO> coupons = future2.get();
            coupons = coupons.stream().distinct().collect(Collectors.toList());
            cartItemListVO.setCartItemsData(cartItemsVOS);
            List<CouponVO> userCoupons = future3.get();
            // 修改优惠卷状态
            updateCouponStatus(coupons, userCoupons);
            cartItemListVO.setCoupons(coupons);
            List<CouponVO> couponVOS = future4.get();
            if (CollectionUtils.isNotEmpty(couponVOS)) {
                userCoupons.addAll(couponVOS);
            }
            List<CouponVO> collect2 = userCoupons.stream().filter(CouponVO::getIsUse).collect(Collectors.toList());
            cartItemListVO.setCouponSize(collect2.size() + coupons.size());
            cartItemListVO.setUserCoupons(userCoupons);
            setDefaultSelectCoupon(totalPrice, cartItemListVO, userCoupons);
            cartItemListVO.setTotalPrice(totalPrice);
            cartItemListVO.setTotalReducePrice(totalReducePrice);
            cartItemListVO.setActivityDescription(activityDescriptionService.getOne(null));
            return Result.success(cartItemListVO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取购物车数据异常:{}", e.getMessage());
            throw new NotFoundException("获取购物车数据异常");
        }
    }

    //@Idempotent(IdempotentContant.NUMBER_HANDLE)
    @Override
    public Result numberHandle(NumberHandleDTO numberHandleDTO) {
        CartItemDO cartItemDO = this.getById(numberHandleDTO.getId());
        if (numberHandleDTO.getType() == 2) {
            if (cartItemDO.getQuantity() == 0) {
                return Result.success("当前商品的数量已经为0了，不可在进行减操作!!!");
            }
        }
        Result result = goodsFeignClient.findGoodsById(cartItemDO.getProductId());
        if (!result.getStatus()) {
            throw new BaseException("查询商品失败");
        }
        Map<String, Object> entry = (Map<String, Object>) result.getEntry();
        Boolean isSample = MapUtils.getBoolean(entry, "isSample");
        if (isSample) {
            return Result.fail("当前商品每个ID限购1份");
        }
        UpdateWrapper updateWrapper = new UpdateWrapper();
        if (numberHandleDTO.getType() == 1) {
            updateWrapper.setSql("quantity = quantity+1");
        } else {
            updateWrapper.setSql("quantity = quantity - 1");
        }
        updateWrapper.eq("id", numberHandleDTO.getId());
        boolean update = this.update(updateWrapper);
        if (update) {
            // 计算价格
            return this.findCartItemList(AssistantContext.getCurrentUid());
        }
        throw new BaseException("添加数量或者修改数量失败");
    }

    //@Idempotent(value = IdempotentContant.ORDER_SELECT, expire = 100)
    @Override
    public Result select(OrderSelectDTO orderSelectDTO) {
        LambdaUpdateWrapper<CartItemDO> uw = Wrappers.lambdaUpdate(CartItemDO.class)
                .set(CartItemDO::getIsSelect, orderSelectDTO.getType())
                .eq(CartItemDO::getId, orderSelectDTO.getId());
        boolean update = this.update(uw);
        if (update) {
            // 计算价格
            return this.findCartItemList(AssistantContext.getCurrentUid());
        }
        throw new BaseException("选中或者取消选中失败");
    }


    @Override
    public Result selectAll(Integer type) {
        if (type == 1) {
            LambdaUpdateWrapper<CartItemDO> uw = Wrappers.lambdaUpdate(CartItemDO.class)
                    .set(CartItemDO::getIsSelect, true)
                    .eq(CartItemDO::getUserId, AssistantContext.getCurrentUid())
                    .eq(CartItemDO::getIsDelete, false);
            boolean b = this.update(uw);
            if (b) {
                // 计算价格
                return this.findCartItemList(AssistantContext.getCurrentUid());
            }
        } else {
            LambdaUpdateWrapper<CartItemDO> uw = Wrappers.lambdaUpdate(CartItemDO.class)
                    .set(CartItemDO::getIsSelect, false)
                    .eq(CartItemDO::getIsDelete, false)
                    .eq(CartItemDO::getUserId, AssistantContext.getCurrentUid());
            boolean b = this.update(uw);
            if (b) {
                // 计算价格
                return this.findCartItemList(AssistantContext.getCurrentUid());
            }
        }
        throw new BaseException("操作失败");
    }

    @Override
    public Result updateSpecifications(UpdateSpecificationsDTO updateSpecificationsDTO) {
        LambdaUpdateWrapper<CartItemDO> uw = Wrappers.lambdaUpdate(CartItemDO.class)
                .set(CartItemDO::getProductId, updateSpecificationsDTO.getItemId())
                .set(CartItemDO::getProductSkuCode, updateSpecificationsDTO.getSkuCode())
                .eq(CartItemDO::getId, updateSpecificationsDTO.getCartId());
        boolean update = this.update(uw);
        return update ? this.findCartItemList(AssistantContext.getCurrentUid()) : Result.fail();
    }

    @Override
    public Result removeCartltemBySkus(List<String> skus) {
        LambdaQueryWrapper<CartItemDO> queryWrapper = Wrappers.lambdaQuery(CartItemDO.class)
                .in(CartItemDO::getProductSkuCode, skus);
        this.remove(queryWrapper);
        return Result.success();
    }

    @Override
    public Result removeCartltemByProductId(Long id) {
        LambdaQueryWrapper<CartItemDO> queryWrapper = Wrappers.lambdaQuery(CartItemDO.class)
                .in(CartItemDO::getProductId, id);
        return this.remove(queryWrapper) ? Result.success() : Result.fail();
    }

    /***
     * 设置默认优惠卷
     * @param totalPrice
     * @param cartItemListVO
     * @param userCoupons
     */
    private void setDefaultSelectCoupon(BigDecimal totalPrice, CartItemListVO cartItemListVO, List<CouponVO> userCoupons) {
        if (CollectionUtils.isNotEmpty(userCoupons)) {
            List<CouponVO> collect = userCoupons.stream().filter(CouponVO::getIsUse).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                List<CouponVO> collect1 = collect.stream().filter(c -> totalPrice.compareTo(c.getMinPoint()) != -1).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(collect1)) {
                    List<CouponVO> collect2 = collect1.stream().sorted(Comparator.comparing(CouponVO::getAmount).reversed()).collect(Collectors.toList());
                    cartItemListVO.setDefaultSelectCoupon(collect2.get(0));
                }
            }
        }
    }

    /**
     * 设置是否可以使用优惠卷
     *
     * @param cartItemsVOS
     * @param cartItemListVO
     */
    private void setIsUseCoupon(List<CartItemVO> cartItemsVOS, CartItemListVO cartItemListVO) {
        List<CartItemVO> collect = cartItemsVOS.stream().filter(c -> !c.getIsSample() && c.getIsSelect()).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(collect)) {
            cartItemListVO.setIsUseCoupon(true);
        }
    }

    /**
     * 修改优惠卷状态
     *
     * @param coupons
     * @param userCoupons
     */
    private void updateCouponStatus(List<CouponVO> coupons, List<CouponVO> userCoupons) {
        for (CouponVO userCoupon : userCoupons) {
            if (CollectionUtils.isNotEmpty(coupons)) {
                if (coupons.contains(userCoupon)) {
                    coupons.remove(userCoupon);
                } else {
                    userCoupon.setIsUse(false);
                }
            }
        }
    }

    /**
     * 维护商品数据
     *
     * @param cartItemsVO
     * @param cartItemGoodsVO
     */
    private void maintenanceData(CartItemVO cartItemsVO, CartItemGoodsVO cartItemGoodsVO) {
        cartItemsVO.setName(cartItemGoodsVO.getName());
        cartItemsVO.setPrice(cartItemGoodsVO.getPrice());
        cartItemsVO.setDisplayDrawingPics(cartItemGoodsVO.getDisplayDrawingPics());
        cartItemsVO.setLabel(cartItemGoodsVO.getLabel());
        cartItemsVO.setActiveGiveProducts(cartItemGoodsVO.getGiveProducts() == null ? new ArrayList<>() : cartItemGoodsVO.getGiveProducts());
        cartItemsVO.setSkuCode(cartItemGoodsVO.getSkuCode());
        cartItemsVO.setIntegration(cartItemGoodsVO.getIntegration());
        cartItemsVO.setProductCategoryId(cartItemGoodsVO.getProductCategoryId());
        cartItemsVO.setStock(cartItemGoodsVO.getStock());
        cartItemsVO.setIsDelete(cartItemGoodsVO.getIsDelete());
        cartItemsVO.setIsPublish(cartItemGoodsVO.getIsPublish());
        cartItemsVO.setSpecifications(cartItemGoodsVO.getSpecifications());
        cartItemsVO.setIsSample(cartItemGoodsVO.getIsSample());
    }

}
